/*
 * Copyright 2014 Graham Smith
 */
package uk.co.wobblycogs.vegas;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.co.wobblycogs.vegas.project.Project;
import uk.co.wobblycogs.vegas.project.ProjectService;
import uk.co.wobblycogs.vegas.scan.MediaFinder;
import uk.co.wobblycogs.vegas.scan.ScanResults;
import uk.co.wobblycogs.vegas.scan.VegasFinder;

/**
 * This application will scan a collection of Sony Vegas project files and
 * generate a list of all the media files used by those projects. It can then
 * check this list for missing media files and optionally recursively scan a
 * folder of media files to build a reverse look up database (e.g. media file X
 * is used in projects Y and Z).
 *
 * @author Graham Smith
 */
public class Scanner {

	private static final Logger logger = LoggerFactory.getLogger(Scanner.class);
	private final List<Path> projectRoots = new ArrayList<>();
	private final List<Path> mediaRoots = new ArrayList<>();
	private Path reportPath;

	public Scanner() {

	}

	public void scan() throws IOException {
		Instant start = Instant.now();

		ScanResults results = new ScanResults();

		MediaFinder mf = new MediaFinder();
		for (Path p : mediaRoots) {
			Files.walkFileTree(p, mf);
		}

		VegasFinder vf = new VegasFinder();
		for (Path p : projectRoots) {
			Files.walkFileTree(p, vf);
		}

		Instant end = Instant.now();
		Duration duration = Duration.between(start, end);
		results.setDuration(duration);

		HTMLReportGenerator report = new HTMLReportGenerator();
		report.generate(results, getReportPath());
	}

	public void addProjectRoot(Path projectRoot) {
		logger.debug("Added project root: {}", projectRoot);
		this.projectRoots.add(projectRoot);
	}

	public void addMediaRoot(Path mediaRoot) {
		logger.debug("Added media root: {}", mediaRoot);
		this.mediaRoots.add(mediaRoot);
	}

	public Path getReportPath() {
		return reportPath;
	}

	public void setReportPath(Path reportPath) {
		logger.debug("Report: {}", reportPath);
		this.reportPath = reportPath;
	}

	public static void main(String[] args) throws IOException {
		//Definition
		Options options = new Options();
		options.addOption("h", "help", false, "Prints this help.");
		options.addOption("p", "projects", true, "Root of projects directory. Required.");
		options.addOption("m", "media", true, "Root of media directory. Required.");
		options.addOption("r", "report", true, "Directory to place the report file in. Optional, defaults to Desktop on Windows and user home everywhere else.");
		options.addOption("rf", "report_filename", true, "File name for the report. Optional, defaults to \"vegas_tools_report.html\".");
		options.addOption("url", "jdbc_url", true, "JDBC database URL. Optional, defaults to \"jdbc:derby:vegas;create=true\".");
		options.addOption("usr", "jdbc_user", true, "Database username. Optional, defaults to \"vegas\".");
		options.addOption("pwd", "jdbc_password", true, "Database password. Optional, defaults to \"password\".");
		options.addOption("drv", "jdbc_driver", true, "Database driver. Optional, defaults to \"org.apache.derby.jdbc.EmbeddedDriver\". If you want to use a different driver it must be present on the classpath.");

		//Parsing
		CommandLineParser parser = new PosixParser();
		CommandLine cmd = null;
		try {
			cmd = parser.parse(options, args);
		} catch (ParseException e) {
			logger.error("Failed to parse parameters", e);
			System.exit(1);
		}

		//Interrogation
		if (cmd.hasOption('h')) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("Scanner", options);
			System.exit(0);
		}

		Scanner s = new Scanner();

		//Project paths
		if (cmd.hasOption("p")) {
			s.addProjectRoot(Paths.get(cmd.getOptionValue("p")));
		} else {
			throw new IllegalArgumentException("The projects option is required.");
		}

		//Media paths
		if (cmd.hasOption("m")) {
			s.addMediaRoot(Paths.get(cmd.getOptionValue("m")));
		} else {
			throw new IllegalArgumentException("The media option is required.");
		}

		//Report
		Path reportDirectory = Paths.get(System.getProperty("user.home"));

		if (SystemUtils.IS_OS_WINDOWS) {
			Path desktop = reportDirectory.resolve("Desktop");
			if (Files.exists(desktop) && Files.isDirectory(desktop)) {
				reportDirectory = desktop;
			}
		}

		if (cmd.hasOption("r")) {
			reportDirectory = Paths.get(cmd.getOptionValue("r"));
		}

		if (!Files.exists(reportDirectory) || !Files.isDirectory(reportDirectory)) {
			throw new IllegalArgumentException("Report directory \"" + reportDirectory + "\" does not exist or is not a directory");
		}

		logger.debug("Report directory: {}", reportDirectory);

		if (cmd.hasOption("rf")) {
			String reportName = cmd.getOptionValue("rf");
			if (!reportName.toLowerCase().endsWith(".html")) {
				reportName += ".html";
			}
			s.setReportPath(reportDirectory.resolve(reportName));
		} else {
			s.setReportPath(reportDirectory.resolve("vegas_tools_report.html"));
		}

		initializeDatabase(cmd);

		//Database
		s.scan();

		Path path = Paths.get("M:\\Videos\\CNCtrl\\Projects\\Stepper Socket Wiring\\Stepper Socket Wiring.vf");
		ProjectService ps = new ProjectService();
		Project p = ps.findByPath(path);
		logger.debug("Found: {} ({})", p.getProjectPath(), p.getId());
	}

	private static void initializeDatabase(CommandLine cmd) {
		Map<String, String> emfSettings = new HashMap<>();

		if (cmd.hasOption("url")) {
			emfSettings.put(PersistenceUtilities.URL_KEY, cmd.getOptionValue("url"));
		}

		if (cmd.hasOption("usr")) {
			emfSettings.put(PersistenceUtilities.USER_KEY, cmd.getOptionValue("usr"));
		}

		if (cmd.hasOption("pwd")) {
			emfSettings.put(PersistenceUtilities.PASSWORD_KEY, cmd.getOptionValue("pwd"));
		}

		if (cmd.hasOption("drv")) {
			emfSettings.put(PersistenceUtilities.DRIVER_KEY, cmd.getOptionValue("drv"));
		}

		PersistenceUtilities pu = PersistenceUtilities.getInstance();
		pu.initializeEntityManagerFactory(emfSettings);
	}

}
